﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using com.lover.astd.updater.json;

namespace com.lover.astd.updater
{
    public partial class MainForm : Form
    {
        private string _fileDownloadBase = "http://www.whohelpyou.com/download/updates/";
        private string _serverMd5File = "http://www.whohelpyou.com/download/astd.jpg";
        private List<String> _filesToDownload = new List<String>();
        private WebClient _wclient;
        private int _filesTotalCount = 0;
        private int _filesDownloaded = 0;
        private bool _downloadCompleted = false;
        private UpdateState _state;
        private class UpdateState
        {
            public int currentStep;
            public int totalStep;
            public int currentProgress;
            public string desc;
            public int currentFileIndex;
            public int totalFiles;
        }
        private delegate void DownloadHandler(IAsyncResult ar);
        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            _state = new UpdateState();
            _state.totalStep = 4; // generateLocalMd5 + downloadServerMd5 + compare + downloadFiles
            _state.currentStep = 1;
            _state.currentProgress = 0;
            _state.desc = "";
            _worker.RunWorkerAsync();
        }

        void _worker_DoWork(object sender, DoWorkEventArgs e)
        {
            _wclient = new WebClient();
            _wclient.DownloadProgressChanged += _wclient_DownloadProgressChanged;
            _wclient.DownloadFileCompleted += _wclient_DownloadFileCompleted;
            startGenerateLocalMd5();
        }

        private void _wclient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            _filesDownloaded++;
            startDownloadFiles();
        }

        private void _wclient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            _state.currentProgress = e.ProgressPercentage;
            _worker.ReportProgress(0, _state);
        }

        private void startGenerateLocalMd5()
        {
            _state.currentStep = 1;
            _state.desc = "正在生成本地文件摘要 ...";
            _worker.ReportProgress(0, _state);
            processUpdate();
        }
        private string randFileUrl(string orig_url)
        {
            return orig_url + "?r=" + new Random().Next();
        }
        private void processUpdate()
        {
            List<string> md5ExceptDir = new List<string>();
            md5ExceptDir.Add("accounts");
            JsonObjectCollection local_md5 = CommonUtils.getLocalMd5(md5ExceptDir);

            _state.currentStep = 2;
            _state.desc = "正在下载服务器文件摘要 ...";
            _worker.ReportProgress(0, _state);
            string content = HttpUtils.getInstance().doGet(randFileUrl(_serverMd5File));
            if (content == null)
            {
                UiUtils.getInstance().error("获取服务器文件摘要失败, 将在下次启动时重试");
                startGame();
                return;
            }

            DebugLogHelper.getInstance().log("正在比较文件摘要 ...");
            _state.currentStep = 3;
            _state.desc = "正在比较 ...";
            _worker.ReportProgress(0, _state);
            JsonTextParser parser = new JsonTextParser();
            JsonObjectCollection server_md5 = (JsonObjectCollection)parser.Parse(content);

            _filesToDownload.Clear();

            IEnumerator<JsonObject> server_enumer = server_md5.GetEnumerator();
            while (server_enumer.MoveNext())
            {
                JsonStringValue server_item = server_enumer.Current as JsonStringValue;
                bool foundInLocal = false;
                IEnumerator<JsonObject> local_enumer = local_md5.GetEnumerator();
                while (local_enumer.MoveNext())
                {
                    JsonStringValue local_item = local_enumer.Current as JsonStringValue;
                    if (local_item.Name == server_item.Name && local_item.Value == server_item.Value)
                    {
                        foundInLocal = true;
                        break;
                    }
                }
                if (!foundInLocal)
                {
                    _filesToDownload.Add(server_item.Name);
                }
            }

            _filesTotalCount = _filesToDownload.Count;
            _filesDownloaded = 0;
            startDownloadFiles();

            while (!_downloadCompleted)
            {
                Thread.Sleep(100);
            }
        }
        private void startDownloadFiles()
        {
            if (_filesToDownload.Count > 0)
            {
                _state.currentStep = 4;
                _state.desc = String.Format("正在下载  {0} / {1}", _filesDownloaded + 1, _filesTotalCount);
                _state.currentFileIndex = _filesDownloaded + 1;
                _state.totalFiles = _filesTotalCount;
                _worker.ReportProgress(0, _state);

                string filename = _filesToDownload[0];
                _filesToDownload.RemoveAt(0);
                DebugLogHelper.getInstance().log(String.Format("正在下载文件{0}, 还剩{1}个文件需要下载", filename, _filesToDownload.Count));
                downloadFile(filename);
            }
            else
            {
                _downloadCompleted = true;
            }
        }

        private void downloadFile(string filename)
        {
            string local_base = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            string server_filename = _fileDownloadBase + filename;
            string local_filename = local_base + filename.Replace('/', '\\');
            // if updater.exe, rename to updater1.exe
            if (filename.Equals("updater.exe")) local_filename = local_base + "updater1.exe";

            // if directory not exits, create it
            FileInfo finfo = new FileInfo(local_filename);
            DirectoryInfo dinfo = finfo.Directory;
            if (!dinfo.Exists) dinfo.Create();
            try
            {
                Uri uri = new Uri(randFileUrl(server_filename));
                _wclient.DownloadFileAsync(uri, local_filename);
            }
            catch (WebException ex)
            {
                UiUtils.getInstance().error("文件下载失败, " + ex.Message);
                return;
            }
        }

        private void startGame()
        {
            DebugLogHelper.getInstance().log("启动游戏中...");
            ProcessStartInfo gameInfo = new ProcessStartInfo();
            gameInfo.FileName = "astd.exe";
            gameInfo.WorkingDirectory = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            gameInfo.WindowStyle = ProcessWindowStyle.Normal;
            gameInfo.Arguments = "from_updater";

            Process proc;
            try
            {
                proc = Process.Start(gameInfo);
                this.Close();
            }
            catch (System.Exception ex)
            {
                UiUtils.getInstance().error("启动游戏失败, 请联系管理员, " + ex.Message);
                return;
            }
        }

        private void btn_close_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            UpdateState state = e.UserState as UpdateState;
            if (state.currentFileIndex > 0)
            {
                // downloading files
                lbl_status.Text = state.desc;
                lbl_progress.Text = String.Format("{0}%", state.currentProgress);
                progress_update.Value = state.currentProgress;
            }
            else
            {
                lbl_status.Text = state.desc;
            }
        }

        private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            DebugLogHelper.getInstance().log("下载线程结束, 准备开始游戏");
            if (_filesToDownload.Count == 0)
            {
                startGame();
            }
        }
    }
}
